/**********************************************************************************************************************
 *
 * Project:    mGameEngine
 * File:       dynamicbody.cpp
 * Author:     twoja stara
 * Created on: 2009-09-25
 *
 **********************************************************************************************************************/

#include "dynamicbody.h"

namespace mGameEngine
{
namespace Physics
{

DynamicBody::DynamicBody() :
    Body(),
    _mass(0.0f), _cMass(), _cMassSpecified(false), _linearDamping(0.1f), _angularDamping(0.1f)
{
}

DynamicBody::DynamicBody(Shape *shape, float mass, float restitution, float staticFriction, float dynamicFriction) :
    Body(shape, restitution, staticFriction, dynamicFriction),
    _mass(mass), _cMass(0.0f, 0.0f, 0.0f), _cMassSpecified(false), _linearDamping(0.1f), _angularDamping(0.1f)
{
}

DynamicBody::~DynamicBody()
{
    // nothing here, everything done in Body::~Body()
}

void DynamicBody::setMass(float mass)
{
    // only physical values
    if(mass <= 0.0f)
    {
        return;
    }

    _mass = mass;

    if(_actor)
    {
        _actor->setMass(_mass);
    }
}
void DynamicBody::setCenterOfMass(const Vector3 & cMass)
{
    _cMass = cMass;
    _cMassSpecified = true;

    if(_actor)
    {
        _actor->setCMassOffsetLocalPosition(NxVec3(cMass));
    }
}

void DynamicBody::setDamping(float linearDamping, float angularDamping)
{
    // only physical values
    if(linearDamping < 0.0f || angularDamping < 0.0f)
    {
        return;
    }

    _linearDamping = linearDamping;
    _angularDamping = angularDamping;

    if(_actor)
    {
        _actor->setLinearDamping(_linearDamping);
        _actor->setAngularDamping(_angularDamping);
    }
}

void DynamicBody::putForce(const Vector3 & force, const Vector3 & radius)
{
    if(_actor)
    {
        _actor->addForceAtLocalPos(NxVec3(force), NxVec3(radius), NX_FORCE, true);
    }
}

void DynamicBody::putImpulse(const Vector3 & impulse, const Vector3 & radius)
{
    if(_actor)
    {
        _actor->addForceAtLocalPos(NxVec3(impulse), NxVec3(radius), NX_IMPULSE, true);
    }
}

void DynamicBody::putAcceleration(const Vector3 &acc, const Vector3 &radius)
{
    if(_actor)
    {
        _actor->addForceAtLocalPos(NxVec3(acc), NxVec3(radius), NX_ACCELERATION, true);
    }
}

void DynamicBody::create(NxScene *scene) const
{
    // no shapes or mass - no body
    if (_shapes.empty() || _mass <= 0.0f)
    {
        return;
    }

    // already created
    if(_created)
    {
        return;
    }

    // create material
    NxMaterialDesc materialDesc;
    materialDesc.restitution = _restitution;
    materialDesc.staticFriction = _staticFriction;
    materialDesc.dynamicFriction = _dynamicFriction;
    _material = scene->createMaterial(materialDesc);

    // create actor descriptor
    NxActorDesc desc;

    // create body descriptor
    NxBodyDesc bodyDesc;
    desc.body = &bodyDesc;
    bodyDesc.mass = _mass;
    bodyDesc.linearDamping = _linearDamping;
    bodyDesc.angularDamping = _angularDamping;

    // create shapes descriptors
    for (List<Shape *>::ConstIterator i = _shapes.begin(); i != _shapes.end(); ++i)
    {
        Shape *shape = *i;
        desc.shapes.pushBack(_createShapeDescriptor(shape));
    }

    // create actor
    _actor = scene->createActor(desc);

    // optionally set center of mass
    if(_cMassSpecified)
    {
        _actor->setCMassOffsetLocalPosition(NxVec3(_cMass));
    }

    // delete descriptors
    for (uint i = 0; i != desc.shapes.size(); ++i)
    {
        delete desc.shapes[i];
    }

    // problems while creating actor
    if(!_actor)
    {
        return;
    }

    // actor is created
    _created = true;
}

}
}

